#ifndef THREADPOOL_H
#define THREADPOOL_H
/**
 * @file ThreadPool.h
 * @brief 线程池实现，用于处理并发任务
 * @author CloudLinker
 * @date 2023-06-14
 * @version 1.0
 * @details 该线程池实现支持动态调整线程数量、任务优先级、暂停/恢复功能和任务取消等高级特性
 */

#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>
#include <atomic>
#include <type_traits>
#include <cassert>

#include "CLink/Utils/Utils.h" // 包含 EnableSingleton 模板类

namespace CLink
{
namespace Utils
{

/**
 * @class ThreadPool
 * @brief 高性能线程池实现，支持任务优先级和动态线程管理
 * @details 该线程池实现了以下功能：
 *          - 单例模式，全局唯一实例
 *          - 动态调整线程数量
 *          - 任务优先级管理
 *          - 线程池暂停/恢复
 *          - 等待所有任务完成
 *          - 任务取消
 *          - 空闲线程自动回收
 */
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4251) // 禁用C4251警告：需要有dll接口的类成员
#endif

class CLINK_FUNCTION  ThreadPool
{
public:
    /**
     * @enum Priority
     * @brief 任务优先级枚举
     */
    enum class Priority
    {
        High,   ///< 高优先级任务，优先执行
        Normal, ///< 普通优先级任务
        Low     ///< 低优先级任务，最后执行
    };

    /**
     * @struct TaskPriority
     * @brief 任务优先级内部表示结构
     */
    struct CLINK_FUNCTION TaskPriority
    {
        int value; ///< 优先级数值，值越大优先级越高
        /**
         * @brief 优先级比较操作符
         * @param other 另一个优先级对象
         * @return 如果当前优先级低于other则返回true
         */
        bool operator<(const TaskPriority &other) const
        {
            return value < other.value;
        }
    };

    /**
     * @brief 初始化线程池
     * @param threads 初始线程数量，如果为0则根据系统自动确定
     * @details 如果threads为0，线程池会根据系统硬件并发数自动确定初始线程数
     * @note 此方法可以在获取实例后调用，用于自定义线程池参数
     */
    void Initialize(size_t threads = 0);

    /**
     * @brief 析构函数
     * @details 会停止所有线程并等待它们完成当前任务
     */
    ~ThreadPool();

    // 核心功能 - 在头文件中实现
    /**
     * @brief 提交任务到线程池
     * @tparam F 函数类型
     * @tparam Args 函数参数类型包
     * @param f 要执行的函数
     * @param args 函数参数
     * @return std::future 包含任务执行结果的future对象
     * @throw std::runtime_error 如果线程池已停止则抛出异常
     * @details 提交的任务会以普通优先级加入队列
     */
    template <class F, class... Args>
    auto Submit(F &&f, Args &&...args)
        -> std::future<typename std::invoke_result_t<F, Args...>>;

    /**
     * @brief 以指定优先级提交任务到线程池
     * @tparam F 函数类型
     * @tparam Args 函数参数类型包
     * @param priority 任务优先级
     * @param f 要执行的函数
     * @param args 函数参数
     * @return std::future 包含任务执行结果的future对象
     * @throw std::runtime_error 如果线程池已停止则抛出异常
     * @details 高优先级的任务会优先被执行
     */
    template <class F, class... Args>
    auto SubmitWithPriority(Priority priority, F &&f, Args &&...args)
        -> std::future<typename std::invoke_result_t<F, Args...>>;

    // 线程管理
    /**
     * @brief 调整线程池大小
     * @param threads 目标线程数量
     * @details 线程数量会被限制在最小和最大线程数之间
     */
    void Resize(size_t threads);

    /**
     * @brief 获取当前线程池中的线程总数
     * @return size_t 线程总数
     */
    size_t TotalThreads() const;

    /**
     * @brief 设置线程池最小线程数
     * @param min_threads 最小线程数
     * @details 如果设置的值大于最大线程数，最小线程数会被调整为最大线程数
     */
    void SetMinThreads(size_t min_threads);

    /**
     * @brief 设置线程池最大线程数
     * @param max_threads 最大线程数
     * @details 如果设置的值小于最小线程数，最大线程数会被调整为最小线程数
     */
    void SetMaxThreads(size_t max_threads);

    /**
     * @brief 获取线程池最小线程数
     * @return size_t 最小线程数
     */
    size_t GetMinThreads() const;

    /**
     * @brief 获取线程池最大线程数
     * @return size_t 最大线程数
     */
    size_t GetMaxThreads() const;

    // 任务管理
    /**
     * @brief 获取当前正在执行的任务数量
     * @return size_t 活跃任务数
     */
    size_t ActiveTasks() const;

    /**
     * @brief 获取当前等待执行的任务数量
     * @return size_t 队列中的任务数
     */
    size_t QueuedTasks() const;

    /**
     * @brief 等待所有任务完成
     * @details 此方法会阻塞调用线程直到所有任务完成
     */
    void WaitForAll();

    /**
     * @brief 等待所有任务完成，带超时
     * @param timeout 最大等待时间
     * @return bool 如果所有任务在超时前完成返回true，否则返回false
     */
    bool WaitForAllFor(std::chrono::milliseconds timeout);

    /**
     * @brief 清空任务队列
     * @details 停止接受新任务，但会继续执行已提交的任务
     */
    void Drain();

    /**
     * @brief 清空任务队列，带超时
     * @param timeout 最大等待时间
     * @details 停止接受新任务，并在指定时间内尝试完成已提交的任务
     */
    void DrainFor(std::chrono::milliseconds timeout);

    /**
     * @brief 清空任务队列并停止线程池
     * @details 停止接受新任务，完成已提交的任务后停止线程池
     */
    void DrainAndStop();

    // 状态控制
    /**
     * @brief 暂停线程池
     * @details 暂停后线程池不会执行新任务，但已经开始执行的任务会继续执行
     */
    void Pause();

    /**
     * @brief 恢复线程池
     * @details 恢复线程池的正常运行，继续执行队列中的任务
     */
    void Resume();

    /**
     * @brief 检查线程池是否处于暂停状态
     * @return bool 如果线程池已暂停返回true，否则返回false
     */
    bool IsPaused() const;

    /**
     * @brief 停止线程池
     * @param immediate 是否立即停止
     * @details 如果immediate为true，会立即停止所有线程，可能会导致任务未完成；
     *          如果为false，会等待当前执行的任务完成后停止
     */
    void Stop(bool immediate = false);

    // 高级控制
    /**
     * @brief 设置是否启用任务取消
     * @param enable 是否启用
     * @details 启用后，当线程池停止时会取消未执行的任务
     */
    void SetTaskCancellation(bool enable);

    /**
     * @brief 检查是否启用了任务取消
     * @return bool 如果启用了任务取消返回true，否则返回false
     */
    bool IsTaskCancellationEnabled() const;

    /**
     * @brief 设置线程忙碌超时时间
     * @param timeout 超时时间
     * @details 如果一个线程执行任务的时间超过此值，线程池可能会创建新线程
     */
    void SetThreadBusyTimeout(std::chrono::milliseconds timeout);

    /**
     * @brief 获取线程忙碌超时时间
     * @return std::chrono::milliseconds 超时时间
     */
    std::chrono::milliseconds GetThreadBusyTimeout() const;

    /**
     * @brief 设置空闲线程收缩间隔
     * @param interval 收缩间隔
     * @details 线程池会每隔此时间检查并可能减少空闲线程数量
     */
    void SetIdleThreadShrinkInterval(std::chrono::milliseconds interval);

    /**
     * @brief 获取空闲线程收缩间隔
     * @return std::chrono::milliseconds 收缩间隔
     */
    std::chrono::milliseconds GetIdleThreadShrinkInterval() const;

private:
    /**
     * @brief 私有构造函数
     * @details 构造函数不接受参数，初始化基本成员变量
     * @note 构造函数设为私有，只能通过 GetInstance() 获取实例
     */
    ThreadPool() : active_tasks_(0),
                    pending_tasks_(0),
                    target_thread_count_(0),
                    min_threads_(1),
                    max_threads_(std::thread::hardware_concurrency() * 2),
                    stop_(false),
                    pause_(false),
                    drain_(false),
                    task_cancellation_(true),
                    threads_adjusted_(false),
                    thread_busy_timeout_(1000),
                    idle_thread_shrink_interval_(5000) {}

    /**
     * @struct PriorityTask
     * @brief 带优先级的任务结构
     * @details 用于在任务队列中存储任务及其优先级
     */
    struct CLINK_FUNCTION PriorityTask
    {
        std::function<void()> function; ///< 任务函数
        TaskPriority priority;          ///< 任务优先级
        /**
         * @brief 任务优先级比较操作符
         * @param other 另一个任务
         * @return 如果当前任务优先级低于other则返回true
         */
        bool operator<(const PriorityTask &other) const
        {
            return priority < other.priority;
        }
    };

    /**
     * @brief 工作线程函数
     * @details 线程池中的每个线程执行此函数，不断从任务队列中获取任务并执行
     */
    void Worker();

    /**
     * @brief 调整线程数量
     * @details 根据当前负载和配置动态调整线程池中的线程数量
     */
    void AdjustThreads();

    /**
     * @brief 收缩空闲线程
     * @details 减少空闲线程数量以节省资源
     */
    void ShrinkIdleThreads();

    /**
     * @brief 监控线程状态
     * @details 监控线程池中线程的状态，并根据需要调整线程数量
     */
    void MonitorThreads();

    /**
     * @brief 将优先级枚举转换为内部优先级值
     * @param p 优先级枚举值
     * @return TaskPriority 对应的内部优先级结构
     */
    TaskPriority PriorityToValue(Priority p) const;

    mutable std::mutex mutex_;                                                 ///< 互斥锁，用于保护共享数据
    std::condition_variable condition_;                                        ///< 条件变量，用于线程间通信
    std::condition_variable drain_condition_;                                  ///< 条件变量，用于清空任务队列
    std::condition_variable wait_condition_;                                   ///< 条件变量，用于等待所有任务完成
    std::vector<std::thread> workers_;                                         ///< 工作线程容器
    std::priority_queue<PriorityTask> tasks_;                                  ///< 任务优先队列
    std::atomic<size_t> active_tasks_{0};                                      ///< 当前活跃任务数量
    std::atomic<size_t> pending_tasks_{0};                                     ///< 当前等待执行的任务数量
    std::atomic<size_t> target_thread_count_{0};                               ///< 目标线程数量
    std::atomic<size_t> min_threads_{1};                                       ///< 最小线程数量
    std::atomic<size_t> max_threads_{std::thread::hardware_concurrency() * 2}; ///< 最大线程数量，默认为CPU核心数的两倍
    std::atomic<bool> stop_{false};                                            ///< 线程池停止标志
    std::atomic<bool> pause_{false};                                           ///< 线程池暂停标志
    std::atomic<bool> drain_{false};                                           ///< 清空任务队列标志
    std::atomic<bool> task_cancellation_{true};                                ///< 任务取消启用标志
    std::atomic<bool> threads_adjusted_{false};                                ///< 线程数量已调整标志
    std::chrono::milliseconds thread_busy_timeout_{1000};                      ///< 线程忙碌超时时间，默认1秒
    std::chrono::milliseconds idle_thread_shrink_interval_{5000};              ///< 空闲线程收缩间隔，默认5秒
};

#ifdef _MSC_VER
#pragma warning(pop) // 恢复之前的警告设置
#endif

/**
 * @brief 优先级转换函数实现
 * @param p 优先级枚举值
 * @return TaskPriority 对应的内部优先级结构
 */
inline ThreadPool::TaskPriority ThreadPool::PriorityToValue(Priority p) const
{
    switch (p)
    {
    case Priority::High:
        return {2};
    case Priority::Normal:
        return {1};
    case Priority::Low:
        return {0};
    default:
        return {1};
    }
}

/**
 * @brief Submit方法的模板实现
 * @tparam F 函数类型
 * @tparam Args 函数参数类型包
 * @param f 要执行的函数
 * @param args 函数参数
 * @return std::future 包含任务执行结果的future对象
 */
template <class F, class... Args>
auto ThreadPool::Submit(F &&f, Args &&...args)
    -> std::future<typename std::invoke_result_t<F, Args...>>
{
    return SubmitWithPriority(Priority::Normal, std::forward<F>(f), std::forward<Args>(args)...);
}

/**
 * @brief SubmitWithPriority方法的模板实现
 * @tparam F 函数类型
 * @tparam Args 函数参数类型包
 * @param priority 任务优先级
 * @param f 要执行的函数
 * @param args 函数参数
 * @return std::future 包含任务执行结果的future对象
 */
template <class F, class... Args>
auto ThreadPool::SubmitWithPriority(Priority priority, F &&f, Args &&...args)
    -> std::future<typename std::invoke_result_t<F, Args...>>
{
    using return_type = typename std::invoke_result_t<F, Args...>;

    if (stop_)
    {
        throw std::runtime_error("Submit on stopped ThreadPool");
    }

    auto task = std::make_shared<std::packaged_task<return_type()>>(
        std::bind(std::forward<F>(f), std::forward<Args>(args)...));

    std::future<return_type> res = task->get_future();

    {
        std::unique_lock<std::mutex> lock(mutex_);
        pending_tasks_++;

        PriorityTask priority_task;
        priority_task.function = [task, this]()
        {
            try
            {
                if (!stop_)
                {
                    (*task)();
                }
            }
            catch (...)
            {
                // 处理可能的异常
            }
            active_tasks_--;
            pending_tasks_--;
            wait_condition_.notify_one();
        };

        priority_task.priority = PriorityToValue(priority);
        tasks_.push(std::move(priority_task));
    }

    condition_.notify_one();
    return res;
}

} // namespace Utils
} // namespace CLink
#endif // THREADPOOL_H